package cn.samler.diandi.api.service.impl;

import cn.samler.diandi.api.entity.User;
import cn.samler.diandi.api.mapper.UserMapper;
import cn.samler.diandi.api.model.db.UserPassportType;
import cn.samler.diandi.api.model.io.Response;
import cn.samler.diandi.api.model.io.request.user.*;
import cn.samler.diandi.api.service.UserService;
import cn.samler.diandi.api.utils.*;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.regex.Pattern;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;

    public UserServiceImpl(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 发送短信验证码
     * @param form 登录表单
     * @return Response
     */
    @Override
    public Response sendSMS(SendSMSForm form) {
        // 腾讯验证码接入验证
        TencentCaptchaForm tencentCaptchaForm = form.getCaptcha();
        boolean verifyResult = TencentCaptchaUtils.getInstance().verify(tencentCaptchaForm.getTicket(),
                tencentCaptchaForm.getRandstr(), IpUtil.getIpAddr(ContextHolderUtil.getRequest()));

        if(verifyResult) { // 验证通过
            if (Pattern.matches("^\\d{11}$", form.getTelephone())) {
                if (BmobSMSUtils.getInstance().send(form.getTelephone()))
                    return new ResponseBuilder().success().msg("发送成功").build();

                return new ResponseBuilder().failure().msg("发送失败").build();
            }

            return new ResponseBuilder().failure().msg("手机号码格式错误").build();
        }

        return new ResponseBuilder().failure().msg("验证失败").build();
    }

    /**
     * 重置密码
     * @param form 表单
     * @return Response
     */
    @Override
    public Response resetPassword(ResetPassword form) {
        Response checkResult = PasswordUtils.checkStrength(form.getPassword());
        if(checkResult.isSuccess()) {
            User user = (User) ContextHolderUtil.getCurrentUser();
            user.setUsername(null);
            user.setPassword(PasswordUtils.getSHA256(form.getPassword()));

            if(userMapper.update(user) > 0)
                return new ResponseBuilder().success().msg("修改成功").data(UserUtil.getAccessTokenMap(user)).build();

            return new ResponseBuilder().failure().msg("修改失败").build();
        }

        return checkResult;
    }

    /**
     * 重置用户名
     * @param form 表单
     * @return Response
     */
    @Override
    public Response resetUsername(ResetUsername form) {
        User user = userMapper.findByName(form.getUsername());
        if(user != null)
            return new ResponseBuilder().failure().msg("该用户名不可用").build();

        user = (User) ContextHolderUtil.getCurrentUser();
        user.setUsername(form.getUsername());
        user.setPassword(null);

        if(userMapper.update(user) > 0)
            return new ResponseBuilder().success().msg("修改成功").build();

        return new ResponseBuilder().failure().msg("修改失败").build();
    }

    /**
     * 原始登录
     *  - 账号密码
     * @param form 登录表单
     * @return Response
     */
    @Override
    public Response login(Login.Origin form) {
        // 腾讯验证码接入验证
        TencentCaptchaForm tencentCaptchaForm = form.getCaptcha();
        boolean verifyResult = TencentCaptchaUtils.getInstance().verify(tencentCaptchaForm.getTicket(),
                tencentCaptchaForm.getRandstr(), IpUtil.getIpAddr(ContextHolderUtil.getRequest()));

        if(verifyResult) { // 验证通过
            User user = userMapper.findByName(form.getUsername());
            if(user != null) {
                if(user.getPassword().equals(PasswordUtils.getSHA256(form.getPassword()))) {
                    return new ResponseBuilder().success().msg("登录成功").data(UserUtil.getAccessTokenMap(user)).build();
                }
            }

            return new ResponseBuilder().failure().msg("账号或密码错误").build();
        }

        return new ResponseBuilder().failure().msg("验证失败").build();
    }

    /**
     * 第三方登录
     *  - 手机号
     * @param form 登录表单
     * @return Response
     */
    @Override
    public Response login(Login.Telephone form) {
        // Bmob短信接入验证
        boolean verifyResult = BmobSMSUtils.getInstance().verify(form.getTelephone(), form.getSmsCode());
        if(verifyResult) { // 验证通过
            User user = userMapper.findByPassport(UserPassportType.TELEPHONE, "$.telephone", form.getTelephone());
            if(user != null)
                return new ResponseBuilder().success().msg("登录成功").data(UserUtil.getAccessTokenMap(user)).build();

            return new ResponseBuilder().failure().msg("手机号未绑定，请在小程序端登录后进行绑定").build();
        }

        return new ResponseBuilder().failure().msg("验证码错误").build();
    }

    /**
     * 第三方登录
     *  - 微信小程序
     * @param form 登录表单
     * @return Response
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Response login(Login.WechatMiniProgram form) {
        WechatMiniProgramAPIUtil util = WechatMiniProgramAPIUtil.getInstance();
        JSONObject json = util.getLoginSession(form.getCode());
        if(json != null) {
            if(json.containsKey("openid")) {
                User user = userMapper.findByPassport(UserPassportType.WECHAT_MINI_PROGRAM, "$.openid", json.getString("openid"));
                if(user == null) {
                    // 自动创建一个用户
                    String password = PasswordUtils.getRandPassword();
                    user = new User();
                    user.setUsername("wx_" + PasswordUtils.getMD5("wx_" + json.getString("openid")).substring(0, 12));
                    user.setPassword(PasswordUtils.getSHA256(password));

                    if(userMapper.insert(user) <= 0)
                        return new ResponseBuilder().failure().msg("服务器错误，登录失败").build();

                    // 绑定passport
                    userMapper.insertPassport(user.getId(), UserPassportType.WECHAT_MINI_PROGRAM, json.toJSONString());
                }

                return new ResponseBuilder().success().msg("登录成功").data(UserUtil.getAccessTokenMap(user)).build();
            }

            log.warn("login failure: " + json);
            return new ResponseBuilder().failure().msg(json.getString("errmsg")).build();
        }

        return new ResponseBuilder().failure().msg("服务器错误").build();
    }

}
